﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using SPAdvancedSearch.Inputs;
using System.Web.UI;
using System.Web;
using System.Text.RegularExpressions;
using SPAdvancedSearch.Utility;

namespace SPAdvancedSearch
{
    /// <summary>
    /// Defines a panel for displaying an advanced search user interface for SharePoint search.
    /// </summary>
    public class AdvancedSearchPanel : WebControl
    {

        #region Constants

        private const string PROPERTY_NAME_ATTRIBUTE = "propName";

        #endregion

        #region Fields

        private HtmlInputButton _searchButton;
        private HtmlInputButton _clearButton;
        private Panel _searchOptionsPanel;
        private List<SearchProperty> _searchProperties;
        private TextBox _targetKeywordInput;
        private string _onSearchClientScript;

        #endregion

        #region Ctor

        /// <summary>
        /// Creates an instance of <see cref="AdvancedSearchPanel"/>.
        /// </summary>
        public AdvancedSearchPanel(List<SearchProperty> searchProperties, TextBox targetKeywordInput)
        {
            _searchProperties = searchProperties;
            _targetKeywordInput = targetKeywordInput;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the client script to execute when a search is performed.
        /// </summary>
        public string OnSearchClientScript
        {
            get { return _onSearchClientScript; }
            set { _onSearchClientScript = value; }
        }

        /// <summary>
        /// Gets the panel that contains the possible search options.
        /// </summary>
        private Panel SearchOptionsPanel
        {
            get
            {
                if (_searchOptionsPanel == null)
                {
                    _searchOptionsPanel = new Panel();
                    _searchOptionsPanel.ID = "advSrchPnl";
                }

                return _searchOptionsPanel;
            }
        }

        /// <summary>
        /// Gets the contained search button.
        /// </summary>
        private HtmlInputButton SearchButton
        {
            get
            {
                if (_searchButton == null)
                {
                    _searchButton = new HtmlInputButton();
                    _searchButton.Value = "Search";
                    _searchButton.Attributes.Add("onclick", "searchButtonClicked()");
                }
                return _searchButton;
            }
        }

        /// <summary>
        /// Gets the contained clear button.
        /// </summary>
        private HtmlInputButton ClearButton
        {
            get
            {
                if (_clearButton == null)
                {
                    _clearButton = new HtmlInputButton();
                    _clearButton.Value = "Clear";
                    _clearButton.Attributes.Add("onclick", "clearButtonClicked()");
                }
                return _clearButton;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Shows or hides the panel.
        /// </summary>
        /// <param name="visible"></param>
        public void ShowPanel(bool visible)
        {
            if (visible)
            {
                this.Attributes.Add("style", "display:block;z-index:10;position:absolute;width:400px;padding:4px;");
            }
            else
            {
                this.Attributes.Add("style", "display:none;z-index:10;position:absolute;width:400px;padding:4px;");
            }
        }

        /// <summary>
        /// Overridden to create the <see cref="AdvancedSearchPanel"/>.
        /// </summary>
        protected override void CreateChildControls()
        {

            try
            {
                this.InitializeSearchOptionsPanel();
                this.Controls.Add(this.SearchOptionsPanel);

                Panel buttonPanel = new Panel();
                buttonPanel.Style.Add(HtmlTextWriterStyle.TextAlign, "right");
                buttonPanel.Controls.Add(this.ClearButton);
                buttonPanel.Controls.Add(new LiteralControl("&nbsp;"));
                buttonPanel.Controls.Add(this.SearchButton);

                this.Controls.Add(buttonPanel);
            }
            catch (Exception e)
            {
                //TODO: who likes to do error handling anyway :)
                Page.Response.Write(e.Message + " " + e.StackTrace);
            }
        }

        /// <summary>
        /// Overridden.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreRender(EventArgs e)
        {
            this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "SPASSearchClick", GenerateSearchButtonClickClientScript(), true);
            this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "SPASClearClick", GenerateClearButtonClickClientScript(), true);
        }

        /// <summary>
        /// Initializes the search options panel.
        /// </summary>
        private void InitializeSearchOptionsPanel()
        {
            Table searchOptionsTable = new Table();
            QueryStringParser parser = new QueryStringParser(Page.Request.QueryString["k"]);

            foreach (SearchProperty prop in _searchProperties)
            {
                // create a row for the name / value pair <tr>
                TableRow row = new TableRow();
                searchOptionsTable.Rows.Add(row);

                ValueControlBase valueControl = prop.GetValueControl();                

                // create the 1st cell <td> and add the label.
                TableCell cell = new TableCell();
                cell.CssClass = "ms-sbcell srch-options";
                row.Cells.Add(cell);

                // create a <label>
                HtmlGenericControl label = new HtmlGenericControl("label");
                label.InnerText = prop.FriendlyName + ":";
                cell.Controls.Add(label);

                // create the 2nd cell <td> and add the display control
                cell = new TableCell();
                row.Cells.Add(cell);

                // get the display control type for this property and append an attribute to use on the client-side
                ISearchPropertyInputControl displayControl = valueControl.GetDisplayControl();
                displayControl.PropertyValue = parser.ParseValueFromQueryString(prop.ManagedPropertyName);

                WebControl webControl = (WebControl)displayControl;
                webControl.Width = Unit.Pixel(250);
                webControl.EnableViewState = false;
                webControl.Attributes.Add(PROPERTY_NAME_ATTRIBUTE, prop.ManagedPropertyName);

                cell.Controls.Add(webControl);
            }

            this.SearchOptionsPanel.Controls.Add(searchOptionsTable);
        }



        /// <summary>
        /// Generates the client-side JavaScript for collecting the value control values.
        /// </summary>
        /// <returns></returns>
        private string GenerateSearchButtonClickClientScript()
        {
            StringBuilder sb = new StringBuilder();
            //TODO: handle multiple search inputs
            sb.Append("function searchButtonClicked()");
            sb.Append("{");
            sb.AppendFormat("   var panel = document.all.{0};", this.ClientID);
            sb.AppendFormat("   var query = new String();");

            sb.Append("         var inputs = panel.getElementsByTagName('INPUT');");
            sb.Append("         for (var i = 0; i < inputs.length; i++)");
            sb.Append("         {");
            sb.AppendFormat("       var propNameAttrib = inputs[i].getAttribute('{0}');", PROPERTY_NAME_ATTRIBUTE);
            sb.Append("             if ( (propNameAttrib) && (inputs[i].value.length > 0) )");
            sb.Append("             {");
            sb.Append("                 query += propNameAttrib + ':\"' + inputs[i].value + '\" ';");
            sb.Append("             }");
            sb.Append("         }");

            sb.Append("         var selects = panel.getElementsByTagName('SELECT');");
            sb.Append("         for (var i = 0; i < selects.length; i++)");
            sb.Append("         {");
            sb.AppendFormat("       var propNameAttrib = selects[i].getAttribute('{0}');", PROPERTY_NAME_ATTRIBUTE);
            sb.Append("             if ( (propNameAttrib) && (selects[i].value.length > 0) )");
            sb.Append("             {");
            sb.Append("                 query += propNameAttrib + ':\"' + selects[i].value + '\" ';");
            sb.Append("             }");
            sb.Append("         }");

            sb.AppendFormat("   var targetInput = document.all.{0};", _targetKeywordInput.ClientID);
            sb.Append("         if (targetInput.value.length > 0)");
            sb.Append("         {");
            sb.Append("             targetInput.value += ' ' + query;");
            sb.Append("         }");
            sb.Append("         else");
            sb.Append("         {");
            sb.Append("             targetInput.value = query;");
            sb.Append("         }");
            sb.AppendFormat("   eval('{0}');", this.OnSearchClientScript);
            sb.Append("}");

            return sb.ToString();
        }


        /// <summary>
        /// Generates the client-side JavaScript for clearing the value control values.
        /// </summary>
        /// <returns></returns>
        private string GenerateClearButtonClickClientScript()
        {
            StringBuilder sb = new StringBuilder();
            //TODO: handle multiple search inputs
            sb.Append("function clearButtonClicked()");
            sb.Append("{");
            sb.AppendFormat("   var panel = document.all.{0};", this.ClientID);
            sb.AppendFormat("   var query = new String();");

            sb.Append("         var inputs = panel.getElementsByTagName('INPUT');");
            sb.Append("         for (var i = 0; i < inputs.length; i++)");
            sb.Append("         {");
            sb.AppendFormat("       var propNameAttrib = inputs[i].getAttribute('{0}');", PROPERTY_NAME_ATTRIBUTE);
            sb.Append("             if (propNameAttrib)");
            sb.Append("             {");
            sb.Append("                 inputs[i].value = '';");
            sb.Append("             }");
            sb.Append("         }");

            sb.Append("         var selects = panel.getElementsByTagName('SELECT');");
            sb.Append("         for (var i = 0; i < selects.length; i++)");
            sb.Append("         {");
            sb.AppendFormat("       var propNameAttrib = selects[i].getAttribute('{0}');", PROPERTY_NAME_ATTRIBUTE);
            sb.Append("             if (propNameAttrib)");
            sb.Append("             {");
            sb.Append("                 selects[i].selectedIndex = 0;");
            sb.Append("             }");
            sb.Append("         }");

            sb.AppendFormat("   var targetInput = document.all.{0};", _targetKeywordInput.ClientID);
            sb.Append("         targetInput.value = '';");
            sb.Append("}");

            return sb.ToString();
        }

        #endregion

        #region Event Handlers

        #endregion
    }
}
